package com.partvoyage.server.service.infopoint;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;
import com.partvoyage.client.service.infopoint.InfoPointService;
import com.partvoyage.server.dao.DataInfoPointDAO;
import com.partvoyage.server.dao.DataInfoPointEntity;
import com.partvoyage.server.service.facebook.FacebookService;
import com.partvoyage.server.service.geoname.GeonameWebService;
import com.partvoyage.shared.FieldVerifier;
import com.partvoyage.shared.InfoPointBean;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class InfoPointServiceImpl extends RemoteServiceServlet implements
		InfoPointService {
	private Logger log = Logger.getLogger(InfoPointServiceImpl.class.getName());

	public List<String> getImgFromFriends(String where) {
		FacebookService fbService = new FacebookService();
		return fbService.getImgFromFriends(where);
	}

	public String greetServer(String input) throws IllegalArgumentException {
		// Verify that the input is valid.
		if (!FieldVerifier.isValidName(input)) {
			// If the input is not valid, throw an IllegalArgumentException back
			// to
			// the client.
			throw new IllegalArgumentException(
					"Name must be at least 4 characters long");
		}

		String serverInfo = getServletContext().getServerInfo();
		String userAgent = getThreadLocalRequest().getHeader("User-Agent");

		// Escape data from the client to avoid cross-site script
		// vulnerabilities.
		input = escapeHtml(input);
		userAgent = escapeHtml(userAgent);

		return "Hello, " + input + "!<br><br>I am running " + serverInfo
				+ ".<br><br>It looks like you are using:<br>" + userAgent;
	}

	public InfoPointBean create(Long projetId, Double latitude,
			Double longitude, String comment, String commentaire, String cout,
			String avecQui, Date quand, String ou, String codePays,
			Integer zoomLevel, Long markerIdDestination) throws Exception {
		DataInfoPointDAO dao = new DataInfoPointDAO();
		DataInfoPointEntity dataInfoPointEntity = new DataInfoPointEntity();
		dataInfoPointEntity.setLatitude(latitude);
		dataInfoPointEntity.setLongitude(longitude);
		dataInfoPointEntity.setComment(comment);
		dataInfoPointEntity.setCommentaire(commentaire);
		dataInfoPointEntity.setQuand(quand);
		dataInfoPointEntity.setCout(cout);
		dataInfoPointEntity.setOu(ou);
		dataInfoPointEntity.setCodePays(codePays);
		dataInfoPointEntity.setAvecQui(avecQui);
		dataInfoPointEntity.setZoomLevel(zoomLevel);
		dataInfoPointEntity.setMarkerIdDestination(markerIdDestination);
		// ProjetDAO projetDAO = new ProjetDAO();
		// ProjetEntity projetEntity = null;
		// try {
		// projetEntity = projetDAO.get(projetId);
		// } catch (EntityNotFoundException e) {
		// throw new Exception("Le projet " + projetId + " n'existe pas");
		// }
		dataInfoPointEntity.setProjetId(projetId);
		dao.put(dataInfoPointEntity);
		InfoPointBean infoPointBean = new InfoPointBean();
		synchronizeEntityVersInfoBean(dataInfoPointEntity, infoPointBean);
		GWT.log("point créé: " + infoPointBean);
		return infoPointBean;
	}

	/**
	 * On pourrait aussi utiliser le service google pour cela
	 * 
	 * @param latitude
	 * @param longitude
	 * @return
	 */
	public String getPlaceName(Double latitude, Double longitude) {
		String placeName = null;
		try {
			placeName = GeonameWebService.getInstance().getPlaceName(latitude,
					longitude);
		} catch (Throwable e) {
			System.out
					.println("Un problème est apparu lors de la récupération du nom du lieu: "
							+ e);
		}
		return placeName;
	}

	public void supprimerPoint(Long infoPointId) {
		if (infoPointId == null) {
			throw new IllegalArgumentException(
					"Erreur de suppression du point, l'id est null");
		}
		DataInfoPointDAO dao = new DataInfoPointDAO();
		DataInfoPointEntity dataInfoPointEntity = null;
		try {
			dataInfoPointEntity = dao.get(infoPointId);
		} catch (EntityNotFoundException e) {

		}
		dao.delete(dataInfoPointEntity);
		System.out.println("suppression du point " + infoPointId);
	}

	public InfoPointBean update(InfoPointBean infoPointBean) throws Exception {
		if (infoPointBean == null) {
			throw new IllegalArgumentException(
					"Erreur de mise à jour du point, le bean est null");
		}
		DataInfoPointDAO dao = new DataInfoPointDAO();
		// DataInfoPointEntity dataInfoPointEntity = null;
		// try {
		// dataInfoPointEntity = dao.get(infoPointBean.getMarkerId());
		// } catch (EntityNotFoundException e) {
		// throw new Exception("Le point  " + infoPointBean.getMarkerId()
		// + " n'existe pas");
		// }
		// dataInfoPointEntity.synchronizeDonnee(infoPointBean);
		// dao.put(dataInfoPointEntity);

		Objectify ofy = ObjectifyService.beginTransaction(); // instead of
																// begin()
		try {
			DataInfoPointEntity dataInfoPointEntity = ofy.get(
					DataInfoPointEntity.class, infoPointBean.getMarkerId());
			dataInfoPointEntity.synchronizeDonnee(infoPointBean);
			ofy.put(dataInfoPointEntity);

			ofy.getTxn().commit();
		} finally {
			if (ofy.getTxn().isActive())
				ofy.getTxn().rollback();
		}

		System.out.println("[server] Info mise à jour " + infoPointBean);
		return infoPointBean;
	}

	public InfoPointBean findById(Long markerId) throws Exception {
		DataInfoPointDAO dao = new DataInfoPointDAO();
		DataInfoPointEntity dataInfoPointEntity = null;
		InfoPointBean infoPointBean = new InfoPointBean();
		try {
			dataInfoPointEntity = dao.get(new Key<DataInfoPointEntity>(
					DataInfoPointEntity.class, markerId));
		} catch (EntityNotFoundException e) {
			return null;
		}
		synchronizeEntityVersInfoBean(dataInfoPointEntity, infoPointBean);

		return infoPointBean;
	}

	private void synchronizeEntityVersInfoBean(
			DataInfoPointEntity dataInfoPointEntity, InfoPointBean infoPointBean) {
		infoPointBean.setMarkerId(dataInfoPointEntity.getId());
		infoPointBean.setLongitude(dataInfoPointEntity.getLongitude());
		infoPointBean.setLatitude(dataInfoPointEntity.getLatitude());
		infoPointBean.setComment(dataInfoPointEntity.getComment());
		infoPointBean.setCommentaire(dataInfoPointEntity.getCommentaire());
		infoPointBean.setCout(dataInfoPointEntity.getCout());
		infoPointBean.setAvecQui(dataInfoPointEntity.getAvecQui());
		infoPointBean.setProjetId(dataInfoPointEntity.getProjetId());
		infoPointBean.setOu(dataInfoPointEntity.getOu());
		infoPointBean.setCodePays(dataInfoPointEntity.getCodePays());
		infoPointBean.setZoomLevel(dataInfoPointEntity.getZoomLevel());
		infoPointBean.setQuand(dataInfoPointEntity.getQuand());
		infoPointBean.setMarkerIdDesination(dataInfoPointEntity
				.getMarkerIdDestination());

	}

	// public List<InfoPointBean> findAll() {
	// List<InfoPointBean> listToReturn = new ArrayList<InfoPointBean>();
	// DataInfoPointDAO dao = new DataInfoPointDAO();
	// Iterable<Key<DataInfoPointEntity>> list = dao.listKeys();
	// for (Key<DataInfoPointEntity> key : list) {
	// DataInfoPointEntity dataInfoBulleMarkerEntity = null;
	// try {
	// dataInfoBulleMarkerEntity = dao.get(key);
	// } catch (EntityNotFoundException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// }
	// InfoPointBean dataInfoPoint = new InfoPointBean();
	// dataInfoPoint.setMarkerId(dataInfoBulleMarkerEntity.getId());
	// dataInfoPoint.setLatitude(dataInfoBulleMarkerEntity.getLatitude());
	// dataInfoPoint
	// .setLongitude(dataInfoBulleMarkerEntity.getLongitude());
	// dataInfoPoint.setComment(dataInfoBulleMarkerEntity.getComment());
	// dataInfoPoint.setCout(dataInfoBulleMarkerEntity.getCout());
	// dataInfoPoint.setAvecQui(dataInfoBulleMarkerEntity.getAvecQui());
	// listToReturn.add(dataInfoPoint);
	// log.info("Marker trouvé id: " + dataInfoPoint.getMarkerId());
	// }
	// return listToReturn;
	// }

	public List<InfoPointBean> findAllByProjetId(Long projetId) {

		List<InfoPointBean> listToReturn = new ArrayList<InfoPointBean>();
		DataInfoPointDAO dao = new DataInfoPointDAO();
		List<DataInfoPointEntity> list = dao.listByProperty("projetId",
				projetId);
		for (DataInfoPointEntity dataInfoPointEntity : list) {
			InfoPointBean infoPointBean = new InfoPointBean();
			synchronizeEntityVersInfoBean(dataInfoPointEntity, infoPointBean);
			listToReturn.add(infoPointBean);
			GWT.log("point trouvé: " + infoPointBean);
		}
		return listToReturn;
	}

	public void deleteAllByProjetId(Long projetId) {
		DataInfoPointDAO dao = new DataInfoPointDAO();
		// dao.deleteKeys(dao.listKeys());
		List<DataInfoPointEntity> list = dao.listByProperty("projetId",
				projetId);
		dao.deleteAll(list);
		list = dao.listAll();
		if (list.size() != 0) {
			dao.deleteAll(list);
			// dao.deleteKeys(dao.listKeys());
		}
		list = dao.listAll();
		if (list.size() != 0) {
			dao.deleteAll(list);
			// dao.deleteKeys(dao.listKeys());
		}

		for (DataInfoPointEntity dIPE : list) {
			Key<DataInfoPointEntity> rootKey = new Key<DataInfoPointEntity>(
					DataInfoPointEntity.class, dIPE.getId());

			GWT.log("entité encore trouve " + rootKey.getId());

		}
		list.clear();
		GWT.log("Les points ");
	}

	/*
	 * public InfoPointBean create(Double latitude, Double longitude, String
	 * comment, String cout, String avecQui) { DataInfoPointEntity create =
	 * dbTool.createInfoPoint(latitude, longitude, comment, cout, avecQui);
	 * InfoPointBean infoPointBean = new InfoPointBean();
	 * infoPointBean.setMarkerId(create.getId());
	 * infoPointBean.setLongitude(longitude);
	 * infoPointBean.setLatitude(latitude);
	 * infoPointBean.setComment(create.getComment());
	 * infoPointBean.setCout(create.getCout());
	 * infoPointBean.setAvecQui(create.getAvecQui()); return infoPointBean; }
	 * 
	 * public InfoPointBean update(Long id, Double latitude, Double longitude,
	 * String comment, String cout, String avecQui) { DataInfoPointEntity
	 * entityUpdqted = dbTool.updateInfoPoint(id, latitude, longitude, comment,
	 * cout, avecQui); InfoPointBean infoPointBean = new InfoPointBean();
	 * infoPointBean.setMarkerId(entityUpdqted.getId());
	 * infoPointBean.setLongitude(longitude);
	 * infoPointBean.setLatitude(latitude);
	 * infoPointBean.setComment(entityUpdqted.getComment());
	 * infoPointBean.setCout(entityUpdqted.getCout());
	 * infoPointBean.setAvecQui(entityUpdqted.getAvecQui()); return
	 * infoPointBean; }
	 * 
	 * public InfoPointBean findByMarkerId(Long markerId) { InfoPointBean
	 * infoPointBean = new InfoPointBean(); DataInfoPointEntity
	 * dataInfoBulleMarkerEntity = dbTool .findByInfoPointId(markerId);
	 * infoPointBean.setMarkerId(dataInfoBulleMarkerEntity.getId());
	 * infoPointBean.setLatitude(dataInfoBulleMarkerEntity.getLatitude());
	 * infoPointBean.setLongitude(dataInfoBulleMarkerEntity.getLongitude());
	 * infoPointBean.setComment(dataInfoBulleMarkerEntity.getComment());
	 * infoPointBean.setCout(dataInfoBulleMarkerEntity.getCout());
	 * infoPointBean.setAvecQui(dataInfoBulleMarkerEntity.getAvecQui()); return
	 * infoPointBean; }
	 * 
	 * public List<InfoPointBean> findAll() { List<InfoPointBean> listToReturn =
	 * new ArrayList<InfoPointBean>(); List<DataInfoPointEntity> list =
	 * dbTool.findAllInfoPoint(); for (DataInfoPointEntity
	 * dataInfoBulleMarkerEntity : list) { InfoPointBean dataInfoPoint = new
	 * InfoPointBean();
	 * dataInfoPoint.setMarkerId(dataInfoBulleMarkerEntity.getId());
	 * dataInfoPoint.setLatitude(dataInfoBulleMarkerEntity.getLatitude());
	 * dataInfoPoint .setLongitude(dataInfoBulleMarkerEntity.getLongitude());
	 * dataInfoPoint.setComment(dataInfoBulleMarkerEntity.getComment());
	 * dataInfoPoint.setCout(dataInfoBulleMarkerEntity.getCout());
	 * dataInfoPoint.setAvecQui(dataInfoBulleMarkerEntity.getAvecQui());
	 * listToReturn.add(dataInfoPoint); } return listToReturn; }
	 * 
	 * public void deleteAll() { dbTool.deleteAll(); }
	 */

	/**
	 * prevent cross-site script vulnerabilities.
	 * 
	 * @param html
	 *            the html string to escape
	 * @return the escaped string
	 */
	private String escapeHtml(String html) {
		if (html == null) {
			return null;
		}
		return html.replaceAll("&", "&amp;").replaceAll("<", "&lt;")
				.replaceAll(">", "&gt;");
	}

}
